package com.jprocms.module.cms.controller.portal.api;

import cn.hutool.core.lang.Assert;
import com.jpro.framework.common.enums.UserTypeEnum;
import com.jpro.framework.common.pojo.CommonResult;
import com.jpro.module.system.api.auth.SmsRegisterReqVO;
import com.jpro.module.system.api.auth.SmsSendReqVO;
import com.jpro.module.system.api.convert.AuthConvert;
import com.jpro.module.system.api.sms.SmsCodeApi;
import com.jpro.module.system.api.user.AdminUserApi;
import com.jpro.module.system.api.user.dto.AdminUserRespDTO;
import com.jpro.module.system.api.user.dto.MemberCreateReqDTO;
import com.jpro.module.system.api.user.dto.MemberRegisterReqVO;
import com.jpro.module.system.api.user.vo.MemberAuthLoginRespVO;
import com.jpro.module.system.api.user.vo.MemberResetPasswordReqVO;
import com.jpro.module.system.api.user.vo.MemberUserRespVo;
import com.jpro.module.system.api.user.vo.SimpleAuthLoginReqVO;
import com.jpro.module.system.enums.sms.SmsSceneEnum;
import com.jprocms.module.cms.api.dto.RegisterConfig;
import com.jprocms.module.cms.controller.admin.mail.vo.EmailCodeSendReqDTO;
import com.jprocms.module.cms.controller.admin.mail.vo.EmailCodeUseReqDTO;
import com.jprocms.module.cms.enums.EmailSceneEnum;
import com.jprocms.module.cms.enums.EnumUserStatus;
import com.jprocms.module.cms.enums.ErrorCodeConstants;
import com.jprocms.module.cms.service.email.EmailCodeService;
import com.jprocms.module.cms.service.globalconfig.GlobalConfigService;
import com.xingyuv.captcha.model.common.ResponseModel;
import com.xingyuv.captcha.model.vo.CaptchaVO;
import com.xingyuv.captcha.service.CaptchaService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.security.PermitAll;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;

import static com.jpro.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.jpro.framework.common.pojo.CommonResult.error;
import static com.jpro.framework.common.pojo.CommonResult.success;
import static com.jpro.framework.common.util.servlet.ServletUtils.getClientIP;
import static com.jpro.module.system.enums.ErrorCodeConstants.AUTH_MOBILE_NOT_EXISTS;
import static com.jprocms.module.cms.api.dto.RegisterConfig.*;
import static com.jprocms.module.cms.constant.CmsSysConstants.FRONT_API;
import static com.jprocms.module.cms.enums.ErrorCodeConstants.*;

/**
 * 会员前台 接口
 *
 * @author jprocms
 */
@Slf4j
@Tag(name = "前台 - 会员前台")
@RestController
@RequestMapping({FRONT_API + "/user"})
public class UserApiController {
    private final AdminUserApi adminUserApi;
    private final GlobalConfigService globalConfigService;
    private final SmsCodeApi smsCodeApi;
    private final CaptchaService captchaService;
    private final EmailCodeService emailCodeService;

    public UserApiController(AdminUserApi adminUserApi, SmsCodeApi smsCodeApi, GlobalConfigService globalConfigService,
                             CaptchaService captchaService, EmailCodeService emailCodeService) {
        this.adminUserApi = adminUserApi;
        this.smsCodeApi = smsCodeApi;
        this.globalConfigService = globalConfigService;
        this.captchaService = captchaService;
        this.emailCodeService = emailCodeService;
    }

    @PermitAll
    @Operation(summary = "获取客户端SM2加密public key")
    @GetMapping("/get-client-public-key")
    public CommonResult<String> getClientPublicKey() {
        return adminUserApi.getClientPublicKey();
    }

    @PermitAll
    @PostMapping("/refresh-token")
    @Operation(summary = "刷新令牌")
    @Parameter(name = "refreshToken", description = "刷新令牌", required = true)
    public CommonResult<MemberAuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
        return adminUserApi.refreshToken(refreshToken);
    }

    @PermitAll
    @Operation(summary = "注册会员")
    @PostMapping("/register")
    public CommonResult<Long> registerMember(@Valid @RequestBody MemberRegisterReqVO reqDTO) {
        final RegisterConfig registerConfig = globalConfigService.getDefGlobalConfig().getRegisterConfig();
        if (!registerConfig.isEnabled()) {
            throw exception(PORTAL_REGISTER_NOT_ENABLE);
        }
        validateRegister(reqDTO, registerConfig);
        Integer status = registerConfig.getVerifyMode() == VERIFY_MODE_MANUAL ? EnumUserStatus.UNCHECK.getStatus() : EnumUserStatus.ENABLE.getStatus();
        MemberCreateReqDTO memberCreateReqDTO = AuthConvert.INSTANCE.convertForMemberCreate(reqDTO);
        memberCreateReqDTO.setUserType(UserTypeEnum.MEMBER.getValue());
        memberCreateReqDTO.setStatus(status);
        final CommonResult<Long> registerMemberResult = adminUserApi.registerMember(memberCreateReqDTO);
        //待后台审核
        if (status.equals(VERIFY_MODE_MANUAL)) {
            //前端特殊标记 -1 待审核会员
            return CommonResult.success(-1L);
        }
        return registerMemberResult;
    }

    @PermitAll
    @Operation(summary = "登录")
    @PostMapping("/cmslogin")
    public CommonResult<MemberUserRespVo> cmslogin(@RequestBody @Valid SimpleAuthLoginReqVO reqVO) {
        return adminUserApi.cmslogin(reqVO);
    }

    @PermitAll
    @GetMapping("/logout")
    @Operation(summary = "登出系统")
    public CommonResult<Boolean> logout(@RequestParam("token") String token) {
        return adminUserApi.logout(token);
    }

    @PostMapping("/send-sms-code")
    @PermitAll
    @Operation(summary = "发送手机验证码")
    public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid SmsSendReqVO reqVO) {
        //先检查图形验证码
        Assert.notNull(reqVO.getCaptchaVerification(), () -> {
            throw exception(CAPTCHA_PARAM_ERROR);
        });
        CaptchaVO captchaVO = new CaptchaVO();
        captchaVO.setCaptchaVerification(reqVO.getCaptchaVerification());
        ResponseModel response = captchaService.verification(captchaVO);
        final CommonResult<AdminUserRespDTO> adminUserRespDTOCommonResult = adminUserApi.selectByMobile(reqVO.getMobile());
        // 验证不通过
        if (!response.isSuccess()) {
            throw exception(CAPTCHA_PARAM_ERROR, response.getRepMsg());
        }
        if (adminUserRespDTOCommonResult.isError() && adminUserRespDTOCommonResult.getData() == null) {
            throw exception(AUTH_MOBILE_NOT_EXISTS);
        }
        // 发送验证码
        smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP()));
        return success(true);
    }

    @PostMapping("/send-email-code")
    @PermitAll
    @Operation(summary = "发送邮件验证码")
    public CommonResult<Boolean> sendEmailCode(@RequestBody @Valid EmailCodeSendReqDTO reqDTO) {
        //先检查图形验证码
        Assert.notNull(reqDTO.getCaptchaVerification(), () -> {
            throw exception(CAPTCHA_PARAM_ERROR);
        });
        CaptchaVO captchaVO = new CaptchaVO();
        captchaVO.setCaptchaVerification(reqDTO.getCaptchaVerification());
        ResponseModel response = captchaService.verification(captchaVO);
        // 验证不通过
        if (!response.isSuccess()) {
            throw exception(CAPTCHA_PARAM_ERROR, response.getRepMsg());
        }
        final CommonResult<AdminUserRespDTO> adminUserRespDTOCommonResult = adminUserApi.selectByEmail(reqDTO.getEmail());
        if (adminUserRespDTOCommonResult.isError() && adminUserRespDTOCommonResult.getData() == null) {
            throw exception(AUTH_MOBILE_NOT_EXISTS);
        }
        // 发送验证码
        emailCodeService.sendEmailCode(reqDTO);
        return success(true);
    }

    @Operation(summary = "手机号码是否存在")
    @GetMapping("/mobileExist")
    public boolean mobileExist(@Parameter(description = "手机号码") @NotBlank String mobile) {
        final CommonResult<AdminUserRespDTO> adminUserRespDTOCommonResult = adminUserApi.selectByMobile(mobile);
        if (adminUserRespDTOCommonResult.isError() && adminUserRespDTOCommonResult.getData() == null) {
            throw exception(COMMON_RPC_SYSTEM_ERROR);
        }
        return adminUserRespDTOCommonResult.getData() != null;
    }

    @Operation(summary = "邮箱地址是否存在")
    @GetMapping("/emailExist")
    public boolean emailExist(@Parameter(description = "邮箱地址") @NotBlank String email) {
        final CommonResult<AdminUserRespDTO> adminUserRespDTOCommonResult = adminUserApi.selectByEmail(email);
        if (adminUserRespDTOCommonResult.isError() && adminUserRespDTOCommonResult.getData() == null) {
            throw exception(COMMON_RPC_SYSTEM_ERROR);
        }
        return adminUserRespDTOCommonResult.getData() != null;
    }

    @Operation(summary = "重置密码")
    @PostMapping({"/reset-password"})
    public CommonResult<Boolean> resetPassword(@RequestBody @Valid MemberResetPasswordReqVO reqVO) {
        AdminUserRespDTO user;
        if (StringUtils.isNotBlank(reqVO.email)) {
            final CommonResult<AdminUserRespDTO> adminUserRespDTOCommonResult = adminUserApi.selectByMobile(reqVO.mobile);
            if(adminUserRespDTOCommonResult.isError()){
                error(COMMON_RPC_SYSTEM_ERROR);
            }
            if(adminUserRespDTOCommonResult.getData()==null){
                error(USER_NOT_EXIST);
            }
            EmailCodeUseReqDTO emailCodeUseReqDTO = new EmailCodeUseReqDTO();
            emailCodeUseReqDTO.setCode(reqVO.getEmailCode());
            emailCodeUseReqDTO.setScene(EmailSceneEnum.MEMBER_REGISTER.getScene());
            emailCodeUseReqDTO.setEmail(reqVO.getEmail());
            emailCodeService.validateEmailCode(emailCodeUseReqDTO);
            user = adminUserRespDTOCommonResult.getData();
        } else if (StringUtils.isNotBlank(reqVO.mobile)) {
            final CommonResult<AdminUserRespDTO> adminUserRespDTOCommonResult = adminUserApi.selectByMobile(reqVO.mobile);
            if(adminUserRespDTOCommonResult.isError()){
                error(COMMON_RPC_SYSTEM_ERROR);
            }
            if(adminUserRespDTOCommonResult.getData()==null){
                error(USER_NOT_EXIST);
            }
            final CommonResult<Boolean> useSmsCodeResult = smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(new SmsRegisterReqVO(reqVO.getMobile(), reqVO.getMobileCode()),
                    SmsSceneEnum.MEMBER_REGISTER.getScene(), getClientIP()));
            if (useSmsCodeResult.isError() || !useSmsCodeResult.getData()) {
                throw exception(CAPTCHA_PARAM_ERROR);
            }
            user = adminUserRespDTOCommonResult.getData();
            reqVO.setId(user.getId());
        } else {
            log.error("邮箱或者手机号不能为空");
            throw exception(RESET_PASSWD_PARAM_ERROR);
        }
        adminUserApi.resetUserPassword(reqVO);
        return success(true);
    }


    private void validateRegister(MemberRegisterReqVO reqDTO, RegisterConfig registerConfig) {
        if (registerConfig.getVerifyMode() == VERIFY_MODE_NONE || registerConfig.getVerifyMode() == VERIFY_MODE_MANUAL) {
            Assert.notNull(reqDTO.getCaptchaVerification(), () -> {
                throw exception(CAPTCHA_PARAM_ERROR);
            });
            CaptchaVO captchaVO = new CaptchaVO();
            captchaVO.setCaptchaVerification(reqDTO.getCaptchaVerification());
            ResponseModel response = captchaService.verification(captchaVO);
            // 验证不通过
            if (!response.isSuccess()) {
                throw exception(CAPTCHA_PARAM_ERROR, response.getRepMsg());
            }
        } else if (registerConfig.getVerifyMode() == VERIFY_MODE_MOBILE) {
            Assert.notNull(reqDTO.getMobileMessageValue(), () -> {
                throw exception(CAPTCHA_PARAM_ERROR);
            });
            final CommonResult<Boolean> useSmsCodeResult = smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(new SmsRegisterReqVO(reqDTO.getMobile(), reqDTO.getMobileMessageValue()),
                    SmsSceneEnum.MEMBER_REGISTER.getScene(), getClientIP()));
            if (useSmsCodeResult.isError() || !useSmsCodeResult.getData()) {
                throw exception(CAPTCHA_PARAM_ERROR);
            }
        } else if (registerConfig.getVerifyMode() == VERIFY_MODE_EMAIL) {
            Assert.notNull(reqDTO.getEmailMessageValue(), () -> {
                throw exception(CAPTCHA_PARAM_ERROR);
            });
            EmailCodeUseReqDTO emailCodeUseReqDTO = new EmailCodeUseReqDTO();
            emailCodeUseReqDTO.setCode(reqDTO.getEmailMessageValue());
            emailCodeUseReqDTO.setScene(EmailSceneEnum.MEMBER_REGISTER.getScene());
            emailCodeUseReqDTO.setEmail(reqDTO.getEmail());
            emailCodeService.validateEmailCode(emailCodeUseReqDTO);
        }
        final CommonResult<AdminUserRespDTO> adminUserRespDTOCommonResult = adminUserApi.selectByUsername(reqDTO.getUsername());
        if (adminUserRespDTOCommonResult.isError() || adminUserRespDTOCommonResult.getData() != null) {
            throw exception(ErrorCodeConstants.USER_NAME_EXIST);
        }
        String mobile = reqDTO.getMobile();
        final CommonResult<AdminUserRespDTO> adminUserMobileQueryRespDTOCommonResult = adminUserApi.selectByMobile(mobile);
        if (StringUtils.isNotBlank(mobile) && (adminUserRespDTOCommonResult.isError() || adminUserMobileQueryRespDTOCommonResult.getData() != null)) {
            throw exception(ErrorCodeConstants.MOBILE_EXIST);
        }
        String email = reqDTO.getEmail();
        final CommonResult<AdminUserRespDTO> adminUserEmailQueryRespDTOCommonResult = adminUserApi.selectByEmail(email);
        if (StringUtils.isNotBlank(email) && (adminUserEmailQueryRespDTOCommonResult.isError() || adminUserEmailQueryRespDTOCommonResult.getData() != null)) {
            throw exception(ErrorCodeConstants.EMAIL_EXIST);
        }
    }
}
